﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;

namespace WebSelfHost.Utility.HttpApi
{
    /// <summary>
    /// Http服务工具类
    /// </summary>
    public class HttpServer
    {
        private int port;
        private TcpListener listener;
        private bool Active;
        private Thread thread;
        private string namespaceScan;
        public Dictionary<string, List<MethodInfo>> getMethodDict;
        public Dictionary<string, List<MethodInfo>> postMethodDict;

        /// <summary>
        /// 构造方法，参数说明
        /// 1.端口号
        /// 2.当前Controller所在的dll名
        /// 3.扫描Controll所在的命名空间 
        /// </summary>
        /// <param name="port">Http端口号</param>
        /// <param name="dllName">dll名</param>
        /// <param name="namespaceScan">扫描的Controller命名空间</param>
        public HttpServer(int port, string dllName, string namespaceScan)
        {
            getMethodDict = new Dictionary<string, List<MethodInfo>>();
            postMethodDict = new Dictionary<string, List<MethodInfo>>();
            this.port = port;
            this.namespaceScan = namespaceScan;
            //扫描namespace下所有的Controller
            Dictionary<string, Type> dict = new Dictionary<string, Type>();
            Assembly assembly = Assembly.Load(dllName);
            Type[] types = assembly.GetTypes();
            foreach (Type type in types)
            {
                if (!type.FullName.Contains(namespaceScan))
                {
                    continue;
                }
                //判断是否具有HttpController属性
                object[] attr = type.GetCustomAttributes(false);
                if (attr.Length == 0)
                {
                    continue;
                }
                //从注解数组中取第一个注解(一个属性可以包含多个注解)
                HttpController myattr = attr[0] as HttpController;
                if (myattr == null)
                    continue;
                dict.Add(myattr.Route, type);
            }
            //循环扫描dict，得到所有的Get方法和Post方法集合
            foreach (string key in dict.Keys)
            {
                Type type = dict[key];
                string route = key;
                if (!route.EndsWith("/"))
                    route += "/";
                if (!route.StartsWith("/"))
                {
                    route = "/" + route;
                }
                MethodInfo[] methodArray = type.GetMethods();//获得所有的方法
                foreach (MethodInfo method in methodArray)
                {
                    //取得属性的特性标签，false表示不获取因为继承而得到的标签
                    object[] attr = method.GetCustomAttributes(false);
                    if (attr.Length == 0)
                    {
                        continue;
                    }
                    //从注解数组中取第一个注解(一个属性可以包含多个注解)
                    foreach (Object obj in attr)
                    {
                        HttpPost post = obj as HttpPost;
                        if (post != null)
                        {
                            if (post.ActionName == "")
                            {
                                string url = route + method.Name;
                                if (postMethodDict.ContainsKey(url))
                                {
                                    List<MethodInfo> methodList = postMethodDict[url];
                                    methodList.Add(method);
                                    postMethodDict[url] = methodList;
                                }
                                else
                                {
                                    List<MethodInfo> methodList = new List<MethodInfo>();
                                    methodList.Add(method);
                                    postMethodDict.Add(url, methodList);
                                }
                            }
                            else
                            {
                                string url = route + post.ActionName;
                                if (postMethodDict.ContainsKey(url))
                                {
                                    List<MethodInfo> methodList = postMethodDict[url];
                                    methodList.Add(method);
                                    postMethodDict[url] = methodList;
                                }
                                else
                                {
                                    List<MethodInfo> methodList = new List<MethodInfo>();
                                    methodList.Add(method);
                                    postMethodDict.Add(url, methodList);
                                }
                            }
                            continue;
                        }
                        HttpGet get = obj as HttpGet;
                        if (get != null)
                        {
                            if (get.ActionName == "")
                            {
                                string url = route + method.Name;
                                if (getMethodDict.ContainsKey(url))
                                {
                                    List<MethodInfo> methodList = getMethodDict[url];
                                    methodList.Add(method);
                                    getMethodDict[url] = methodList;
                                }
                                else
                                {
                                    List<MethodInfo> methodList = new List<MethodInfo>();
                                    methodList.Add(method);
                                    getMethodDict.Add(url, methodList);
                                }
                            }
                            else
                            {
                                string url = route + get.ActionName;
                                if (getMethodDict.ContainsKey(url))
                                {
                                    List<MethodInfo> methodList = getMethodDict[url];
                                    methodList.Add(method);
                                    getMethodDict[url] = methodList;
                                }
                                else
                                {
                                    List<MethodInfo> methodList = new List<MethodInfo>();
                                    methodList.Add(method);
                                    getMethodDict.Add(url, methodList);
                                }
                            }
                            continue;
                        }
                    }
                }

            }
            thread = new Thread(Listen);
        }



        /// <summary>
        /// 监听
        /// </summary>
        private void Listen()
        {
            ProcessUtils.KillPort(port);
            listener = new TcpListener(IPAddress.Any, port);
            listener.Start();
            while (Active)
            {
                try
                {
                    TcpClient client = listener.AcceptTcpClient();
                    new Thread(new ThreadStart(new HttpProcessor(client, getMethodDict, postMethodDict).Process)).Start();
                    Thread.Sleep(1);
                }
                catch (Exception ex)
                {

                }
            }
        }

        /// <summary>
        /// 开启服务
        /// </summary>
        public void Start()
        {
            Active = true;
            thread.Start();
        }


        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            Active = false;
            try
            {
                listener.Stop();
            }
            catch { }
        }
    }
}
